/*
 * @Description: 资源信息
 * @Author: DHL
 * @Date: 2022-03-14 17:13:43
 * @LastEditors: DHL
 * @LastEditTime: 2023-01-09 15:23:22
 */

import { defineComponent, computed, onMounted, reactive, ref, watch } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { assign, cloneDeep, differenceBy, intersectionBy } from 'lodash-es'
import { TwTableOptions } from '/@/types/table.d'
import { arrayRemoveItem, getTreeParentName, listToTree } from '/@/utils/twUtils'
import { apiProjectList } from '/@/api/system/project'
import { ProjectListResultModel, ProjectModel } from '/@/api/system/model/projectModel'
import { ResourceModel, ResourcePageParams } from '/@/api/system/model/resourceModel'
import {
  apiResourceDeleteById,
  apiResourceSaveResourceApi,
  apiResourceSearchList,
  apiResourceUpdateById,
  apiResourceUpdateStatusById
} from '/@/api/system/resource'
import { ApiGroupModel } from '/@/api/system/model/apiGroupModel'
import {
  apiApiGroupDeleteById,
  apiApiGroupSearchTree,
  apiApiGroupUpdateById
} from '/@/api/system/apiGroup'
import { ApiModel } from '/@/api/system/model/apiModel'
import { apiApiListApiIdsByResourceId, apiApiSearchList, apiApiUpdateById } from '/@/api/system/api'
import { arraySerializeToStr } from '/@/utils/twUtils'

import type Node from 'element-plus/es/components/tree/src/model/node'
import type { DragEvents } from 'element-plus/es/components/tree/src/model/useDragNode'
import { usePermission } from '/@/hooks/web/permission'
import { stringUtils } from '/@/utils/stringUtils'

import resourceForm from './form.vue'
import apiForm from './apiForm.vue'
import apiGroupForm from './apiGroupForm.vue'
import { Splitpanes, Pane } from 'splitpanes'
import 'splitpanes/dist/splitpanes.css'

export default defineComponent({
  name: 'Resource',
  components: { resourceForm, apiForm, apiGroupForm, Splitpanes, Pane },
  setup(props) {
    //////////////////////////////////////////////////
    // 属性
    //////////////////////////////////////////////////

    const loading = ref(false)

    const { hasPermission } = usePermission()

    /**
     * 表格数据
     */
    const tableData = ref()

    /**
     * 查询表单
     */
    const searchFormRef = ref()

    /**
     * 数据列表
     */
    const tableRef = ref()

    /**
     * 表单
     */
    const formRef = ref()

    /**
     * 是否有选中的行
     */
    const isSelectRows = computed(() => {
      let selectRows: Array<ResourceModel> = []
      if (tableRef.value) {
        selectRows = tableRef.value.getSelectRows()
      }
      return selectRows.length < 1
    })

    /**
     * 项目列表
     */
    const projectList = ref([] as Array<ProjectModel>)

    /**
     * 资源集合
     */
    const resourceList = ref()

    /**
     * 资源tree table是否展开
     */
    const resourceTreeOpen = ref(false)

    //////////////////////////////////////////////////
    // 查询表单
    //////////////////////////////////////////////////

    const defaultSearchForm = {
      parentResId: '', // 父级编码
      name: '', // 资源名称
      url: '', // 资源路径
      resType: '', // 资源类型
      iconCls: '', // 资源图标
      resSeq: 0, // 顺序
      target: '', // 目标
      description: '', // 资源描述
      status: '', // 资源状态(0：无效；1：有效)
      islog: '', // 是否记录日志（0：无效；1：有效）
      iscache: '', // 是否缓存（0-否，1-是）
      projectId: 'SYS' // 项目ID
    }

    /**
     * 查询表单
     */
    const searchForm = reactive(cloneDeep(defaultSearchForm))

    //////////////////////////////////////////////////
    // 表格
    //////////////////////////////////////////////////

    /**
     * 表格配置
     */
    const tableOptions = reactive<TwTableOptions>({
      id: 'resourceTable',
      stripe: false,
      sortConfig: {
        defaultSort: [{ field: 'resSeq', order: 'asc' }]
      },
      treeConfig: {
        rowField: 'id',
        parentField: 'parentResId'
      },
      pagerConfig: {
        enabled: false
      },
      radioConfig: {
        strict: false,
        trigger: 'cell',
        visibleMethod({ row }) {
          return row.resType === '0'
        }
      },
      columns: [
        {
          type: 'radio',
          fixed: 'left',
          title: '',
          width: 40
        },
        { type: 'seq', fixed: 'left', title: '序号', width: 50 },
        {
          field: 'name',
          fixed: 'left',
          title: '资源名称',
          sortable: false,
          treeNode: true,
          minWidth: 260,
          slots: { default: 'resName' }
        },
        { field: 'id', title: '编号', sortable: false, width: 200 },
        { field: 'url', title: '资源路径', sortable: false, width: 200 },
        {
          field: 'resSeq',
          title: '顺序',
          sortable: false,
          width: 110,
          slots: { default: 'resSeq' }
        },
        {
          field: 'status',
          title: '资源状态',
          sortable: false,
          width: 90,
          slots: { default: 'resStatus' },
          params: { dict: 'TWRS' }
        },
        {
          field: 'iscache',
          title: '开启缓存',
          sortable: false,
          width: 90,
          slots: { default: 'resIscache' },
          params: { dict: 'ISCACHE' }
        },
        {
          field: 'resType',
          title: '资源类型',
          sortable: false,
          width: 80,
          params: { dict: 'RESOURCE_TYPE' }
        },
        {
          field: 'openType',
          title: '打开模式',
          sortable: false,
          width: 80,
          params: { dict: 'RESOURCE_OPEN_TYPE' }
        },
        { title: '操作', fixed: 'right', width: 100, slots: { default: 'action' } }
      ]
    })

    /**
     * 绑定事件
     */
    const tableEvents = reactive({
      cellDblclick(params: { row: ResourceModel }) {
        if (hasPermission('RESOURCE-GETBYID')) {
          handleOpenForm('view', params.row)
        } else {
          ElMessage.warning('无权限访问')
        }
      },
      radioChange(params: { newValue: any }) {
        if (params.newValue) {
          handleSearchApiByResourceId()
        } else {
          api.selectApis = []
          handleApiGroupBindCount()
        }
      }
    })

    /**
     * 监听折叠展开
     */
    watch(resourceTreeOpen, (val: boolean) => {
      tableRef.value.tableInstance.setAllTreeExpand(resourceTreeOpen.value)
    })

    //////////////////////////////////////////////////
    // 函数
    //////////////////////////////////////////////////

    /**
     * 查询表格数据函数
     * @param queryParams
     */
    function searchList(queryParams: ResourcePageParams) {
      loading.value = true
      apiResourceSearchList(
        assign(queryParams, searchForm, {
          parentResId: 'all'
        })
      )
        .then((result) => {
          resourceList.value = result?.data
          const treeList = listToTree(result?.data, 'id', 'parentResId', '')
          tableData.value = treeList
        })
        .catch(() => {})
        .finally(() => {
          loading.value = false
        })
    }

    /**
     * 查询表格数据
     */
    function handleSearch() {
      tableRef.value.handleQuery()
    }

    /**
     * 刷新
     */
    function handleRefresh() {
      tableRef.value.handleReload()
    }

    /**
     * 重置
     */
    function handleReset() {
      assign(searchForm, cloneDeep(defaultSearchForm))
      tableRef.value.handleQuery()
    }

    /**
     * 批量删除
     */
    function handleDelete(row?: ResourceModel) {
      if (!row) {
        ElMessage.warning('请选择需要删除的数据')
        return
      }

      ElMessageBox.confirm(`此操作将删除1条记录, 是否继续?`, '删除提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      })
        .then(() => {
          loading.value = true

          apiResourceDeleteById(`${row.id}`)
            .then((result) => {
              if (result?.success) {
                handleRefresh()

                ElMessage.success(result.message)
              } else {
                ElMessage.error(result?.message)
              }
            })
            .catch(() => {})
            .finally(() => {
              loading.value = false
            })
        })
        .catch(() => {
          ElMessage.info('删除被取消了')
        })
    }

    /**
     * 弹出表单
     */
    function handleOpenForm(action: string, row?: ResourceModel) {
      const projectObj = getProjectObj(searchForm.projectId)

      if (stringUtils.isNotEmpty(projectObj.id)) {
        row = assign({}, row, {
          projectId: projectObj.id,
          projectName: projectObj.name
        })
      }

      let selectRow = tableRef.value.getSelectRows()

      if (action === 'edit') {
        selectRow = row
      }

      const parentNames = getTreeParentName(
        resourceList.value,
        'id',
        'parentResId',
        'name',
        selectRow
      )

      if (action === 'edit') {
        arrayRemoveItem(parentNames, row?.name)
      }

      formRef.value.handleOpen(action, row, selectRow, parentNames)
    }

    /**
     * 根据主键更新
     */
    function handleUpdateById(row: ResourceModel) {
      loading.value = true

      apiResourceUpdateById(row)
        .then((result) => {
          if (result?.success) {
            // 刷新表格数据
            handleRefresh()

            ElMessage.success(result.message)
          } else {
            ElMessage.error(result?.message)
          }
        })
        .catch(() => {})
        .finally(() => {
          loading.value = false
        })
    }

    /**
     * 更新资源状态
     */
    function handleUpdateStatusById(row: ResourceModel) {
      apiResourceUpdateStatusById(row.id, row.status)
        .then((result) => {
          if (result?.success) {
            // 刷新表格数据
            handleRefresh()

            ElMessage.success(result.message)
          } else {
            ElMessage.error(result?.message)
          }
        })
        .catch(() => {})
        .finally(() => {
          loading.value = false
        })
    }

    /**
     * 查询项目列表
     */
    function handleSearchProjectList() {
      apiProjectList({}).then((result: ProjectListResultModel) => {
        if (result?.success && result.data) {
          projectList.value = result.data

          // if (projectList.value && projectList.value.length > 0) {
          //   searchForm.projectId = `${projectList.value[0].id}`

          //   handleSearchApiGroup()
          // }
        }
      })
    }

    //////////////////////////////////////////////////
    // 已绑定api模块
    //////////////////////////////////////////////////
    const resourceApi = reactive({
      loading: false,
      // api表格数据
      tableData: [] as Nullable<Array<ApiModel>>,
      tableOptions: {
        id: 'resourceApiTable',
        rowConfig: {
          keyField: 'id'
        },
        sortConfig: {
          defaultSort: [{ field: 'apiSeq', order: 'asc' }]
        },
        checkboxConfig: {
          reserve: false
        },
        columns: [
          { type: 'seq', title: '序号', width: 50 },
          { field: 'apiGroupName', title: '组名称', sortable: false, width: 150 },
          { field: 'name', title: 'API名称', sortable: false, minWidth: 150 },
          { field: 'url', title: 'API路径', sortable: false, width: 150 },
          {
            field: 'apiType',
            title: '类型',
            sortable: false,
            width: 100,
            params: { dict: 'API_TYPE' }
          },
          {
            field: 'apiSeq',
            title: '顺序',
            sortable: false,
            width: 110
          },
          {
            field: 'status',
            title: '资源状态',
            sortable: false,
            width: 90,
            params: { dict: 'TWRS' }
          },
          {
            field: 'islog',
            title: '记录日志',
            sortable: false,
            width: 90,
            params: { dict: 'ISLOG' }
          },
          { field: 'description', title: '资源描述', sortable: false, width: 150 }
        ]
      }
    })
    /**
     * 根据资源ID查询已绑定的api集合
     * @param resourceId
     */
    function handleSearchApiByResourceId() {
      // 选中的资源
      const selectRes = tableRef.value.getSelectRows()

      resourceApi.loading = true
      apiApiListApiIdsByResourceId(selectRes?.id)
        .then((result) => {
          if (result?.success && result.data) {
            resourceApi.tableData = result.data
            api.selectApis = result.data
            handleResApisChecked()
            handleApiGroupBindCount()
          }
        })
        .catch(() => {})
        .finally(() => {
          resourceApi.loading = false
        })
    }

    //////////////////////////////////////////////////
    // 右侧api模块
    //////////////////////////////////////////////////
    /**
     * api
     */
    const api = reactive({
      saveResApiLoading: false,
      projectId: '', // 项目ID
      treeKeyWord: '', // api group过滤关键字
      groupData: [] as Array<ApiGroupModel>, // api group list集合
      groupTreeData: [], // api group tree集合

      // api group tree 配置
      treeProps: {
        label: 'name',
        children: 'children',
        disabled: 'false'
      },
      // api group 选中节点
      selectTreeNode: { id: '', parentId: '' },
      loading: false,

      // api选中集合
      selectApis: [] as Array<ApiModel>,

      // api表格数据
      tableData: [] as Nullable<Array<ApiModel>>,
      tableOptions: {
        id: 'apiTable',
        rowConfig: {
          keyField: 'id'
        },
        sortConfig: {
          defaultSort: [{ field: 'apiSeq', order: 'asc' }]
        },
        checkboxConfig: {
          reserve: false
        },
        columns: [
          { type: 'checkbox', title: '复选', width: 40 },
          { type: 'seq', title: '序号', width: 50 },
          { field: 'name', title: 'API名称', sortable: false, width: 150 },
          { field: 'url', title: 'API路径', sortable: false, minWidth: 150 },
          {
            field: 'apiType',
            title: '类型',
            sortable: false,
            width: 100,
            params: { dict: 'API_TYPE' }
          },
          {
            field: 'apiSeq',
            title: '顺序',
            sortable: false,
            width: 110,
            slots: { default: 'apiSeq' }
          },
          {
            field: 'status',
            title: '资源状态',
            sortable: false,
            width: 90,
            slots: { default: 'apiStatus' },
            params: { dict: 'TWRS' }
          },
          {
            field: 'islog',
            title: '记录日志',
            sortable: false,
            width: 90,
            slots: { default: 'apiIslog' },
            params: { dict: 'ISLOG' }
          },
          { field: 'description', title: '资源描述', sortable: false, width: 150 },
          { field: 'updater', title: '更新人', sortable: false, width: 150 },
          { field: 'updateDate', title: '更新时间', sortable: false, width: 150 }
        ]
      },
      tableEvents: {
        checkboxChange(params: { checked: boolean; row: ApiModel }) {
          api.selectApis = differenceBy(api.selectApis, [params.row], 'id')
          if (params.checked) {
            api.selectApis.push(params.row)
          }
        },
        checkboxAll(params: { checked: boolean }) {
          if (api.tableData && api.tableData.length > 0) {
            api.selectApis = differenceBy(api.selectApis, api.tableData, 'id')
            if (params.checked) {
              api.selectApis.push(...api.tableData)
            }
          }
        }
      }
    })

    const apiGroupRef = ref()
    const apiGroupFormRef = ref()

    const apiTableRef = ref()
    const apiFormRef = ref()

    //////////////////////////// api group ////////////////////////////

    /**
     * 查询api组
     */
    function handleSearchApiGroup() {
      const selectRes = tableRef.value.getSelectRows()

      apiApiGroupSearchTree({ projectId: api.projectId, resourceId: selectRes?.id }).then(
        (result) => {
          if (result?.success) {
            api.groupData = result.data ? result.data : []
            handleApiGroupBindCount()
          }
        }
      )
    }

    /**
     * 设置已绑定api数量
     */
    function handleApiGroupBindCount() {
      if (api.groupData && api.groupData.length > 0) {
        api.groupData.forEach((item) => {
          let count = 0
          api.selectApis.forEach((apiItem) => {
            if (item.id === apiItem.apiGroupId) {
              count++
            }
          })
          item.bindCount = count
        })
      }

      api.groupTreeData = listToTree(api.groupData, 'id', 'parentId', '') as []

      api.groupTreeData.forEach((item) => {
        getChildrenBindCount(item)
      })
    }

    /**
     * 递归计算子节点绑定数量
     */
    function getChildrenBindCount(node: any) {
      if (node.children && node.children.length > 0) {
        let count = 0
        node.children?.forEach((chItem: { bindCount: number }) => {
          count = count + chItem.bindCount

          getChildrenBindCount(chItem)
        })
        node.bindCount = count
      }
    }

    /**
     * api组过滤
     */
    watch(
      () => api.treeKeyWord,
      (val: string) => {
        apiGroupRef.value!.filter(val)
      }
    )

    /**
     * api组过滤
     */
    function handleFilterApiGroup(value: string, data: any) {
      if (!value) return true
      return data.name.includes(value)
    }

    /**
     * 节点点击
     */
    function handleNodeClick(treeNode: any) {
      api.selectTreeNode = treeNode
      apiTableRef.value.handleQuery()
    }

    /**
     * 弹出api group表单
     * @param action
     * @param row
     */
    function handleShowApiGroupForm(action: string, row?: ApiGroupModel) {
      const projectObj = getProjectObj(api.projectId)

      let treeNode = { parentId: '' }
      let parentId = ''
      if (action === 'add') {
        treeNode = api.selectTreeNode
        parentId = api.selectTreeNode.id
      } else {
        treeNode = row || { parentId: '' }
        parentId = treeNode.parentId
      }

      const pnameList = getTreeParentName(api.groupData, 'id', 'parentId', 'name', treeNode)

      apiGroupFormRef.value.handleOpen(
        action,
        {
          projectId: projectObj.id,
          projectName: projectObj.name,
          apiGroupPid: parentId,
          parentGroupName: pnameList.join(' - ')
        },
        row
      )
    }

    /**
     * 刷新api group
     */
    function handleApiGroupRefresh() {
      handleSearchApiGroup()
    }

    /**
     * 删除api group
     * @param row
     */
    function handleDeleteApiGroup(row: ApiGroupModel) {
      ElMessageBox.confirm(`此操作将删除1条记录, 是否继续?`, '删除提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      })
        .then(() => {
          apiApiGroupDeleteById(row.id)
            .then((result) => {
              if (result?.success) {
                handleSearchApiGroup()
                ElMessage.success(result.message)
              } else {
                ElMessage.error(result?.message)
              }
            })
            .catch(() => {})
            .finally(() => {})
        })
        .catch(() => {
          ElMessage.info('删除被取消了')
        })
    }

    /**
     * api group拖拽
     */
    function handleApiGroupDrop(draggingNode: Node, dropNode: Node, dropType: any, ev: DragEvents) {
      let pid = ''
      if ('inner' === dropType) {
        pid = dropNode.data.id
      } else {
        pid = dropNode.data.parentId
      }

      if (stringUtils.isEmpty(pid)) {
        return
      }

      let nodeData: ApiGroupModel = draggingNode.data as ApiGroupModel
      nodeData.parentId = pid

      apiApiGroupUpdateById(nodeData).then((result) => {
        if (result?.success) {
          ElMessage.success(result.message)
        } else {
          ElMessage.error(result?.message)
        }
      })
    }

    /**
     * tree 展开/折叠
     */
    function handleExpand(expand: boolean) {
      apiGroupRef.value.store._getAllNodes().forEach((item: { expanded: boolean }) => {
        item.expanded = expand
      })
    }

    //////////////////////////// api ////////////////////////////

    /**
     * 查询api列表
     * @param queryParams
     */
    function searchApiList(queryParams: ResourcePageParams) {
      api.loading = true
      apiApiSearchList(
        assign(queryParams, searchForm, {
          projectId: api.projectId,
          apiGroupId: api.selectTreeNode.id
        })
      )
        .then((result) => {
          api.tableData = result?.data
          handleResApisChecked()
        })
        .catch(() => {})
        .finally(() => {
          api.loading = false
        })
    }

    /**
     * 资源配置的api集合回显
     */
    function handleResApisChecked() {
      if (api.tableData && api.tableData.length > 0) {
        apiTableRef.value.tableInstance.setAllCheckboxRow(false)
        const checkedRows = intersectionBy(api.selectApis, api.tableData, 'id')
        checkedRows.forEach((item) => {
          apiTableRef.value.tableInstance.setCheckboxRow(item, true)
        })
      }
    }

    /**
     * 批量更新Api信息
     */
    function handleShowApiForm() {
      const projectObj = getProjectObj(api.projectId)

      const pnameList = getTreeParentName(
        api.groupData,
        'id',
        'parentId',
        'name',
        api.selectTreeNode
      )
      apiFormRef.value.handleOpen({
        projectId: projectObj.id,
        projectName: projectObj.name,
        apiGroupPid: api.selectTreeNode.id,
        parentGroupName: pnameList.join(' - ')
      })
    }

    /**
     * 刷新api
     */
    function handleApiRefresh() {
      handleSearchApiGroup()
      apiTableRef.value.handleQuery()
    }

    /**
     * 根据主键更新api
     * @param row
     */
    function handleApiUpdateById(row: ApiModel) {
      api.loading = true
      apiApiUpdateById(row)
        .then((result) => {
          if (result?.success) {
            // 刷新表格数据
            apiTableRef.value.handleQuery()

            ElMessage.success(result.message)
          } else {
            ElMessage.error(result?.message)
          }
        })
        .catch(() => {})
        .finally(() => {
          api.loading = false
        })
    }

    /**
     * 绑定资源api
     */
    function handleSaveResourceApi() {
      // 选中的资源
      const selectRes = tableRef.value.getSelectRows()

      if (!selectRes) {
        ElMessage.warning('请选择资源')
        return
      }
      if (!api.selectApis || api.selectApis.length == 0) {
        ElMessage.warning('请选择接口')
        return
      }

      const apiIds = arraySerializeToStr(api.selectApis, 'id')

      api.saveResApiLoading = true

      apiResourceSaveResourceApi(selectRes.id, apiIds)
        .then((result) => {
          if (result?.success) {
            handleApiGroupBindCount()
            ElMessage.success(result.message)
          } else {
            ElMessage.error(result?.message)
          }
        })
        .catch(() => {})
        .finally(() => {
          api.saveResApiLoading = false
        })
    }

    //////////////////////////// api 抽屉 ////////////////////////////
    const apiDrawer = reactive({
      show: false,
      title: ''
    })

    /**
     * 显示api抽屉
     */
    function handleShowApi() {
      const selectRes = tableRef.value.getSelectRows()

      if (selectRes.length === 0) {
        ElMessage.warning('请选择左侧资源配置接口')
        return
      }

      api.projectId = searchForm.projectId

      apiDrawer.title = `${selectRes.name}配置接口`
      apiDrawer.show = true

      handleSearchApiGroup()
    }

    /**
     * 关闭api抽屉
     */
    function handleApiClose() {
      handleSearchApiByResourceId()
      apiDrawer.show = false
    }

    //////////////////////////////////////////////////
    // 生命周期
    //////////////////////////////////////////////////
    onMounted(() => {
      handleSearchProjectList()
    })

    //////////////////////////////////////////////////
    // utils
    //////////////////////////////////////////////////

    /**
     * 根据projectId获取对象
     * @param projectId
     */
    function getProjectObj(projectId: string) {
      const selectProject = projectList.value.filter((item) => {
        return item.id === projectId
      })

      if (selectProject && selectProject.length > 0) {
        return selectProject[0]
      }

      return { id: '', name: '' }
    }

    return {
      loading,
      tableData,
      searchFormRef,
      tableRef,
      formRef,
      searchForm,
      resourceTreeOpen,
      tableOptions,
      tableEvents,
      isSelectRows,
      projectList,
      api,
      apiGroupRef,
      apiTableRef,
      apiFormRef,
      apiGroupFormRef,
      searchList,
      handleSearch,
      handleRefresh,
      handleReset,
      handleDelete,
      handleOpenForm,
      handleUpdateById,
      handleFilterApiGroup,
      handleSearchApiGroup,
      searchApiList,
      handleApiRefresh,
      handleShowApiForm,
      handleNodeClick,
      handleApiUpdateById,
      handleSaveResourceApi,
      handleShowApiGroupForm,
      handleApiGroupRefresh,
      handleDeleteApiGroup,
      handleApiGroupDrop,
      handleExpand,
      apiDrawer,
      handleShowApi,
      handleApiClose,
      resourceApi,
      handleSearchApiByResourceId,
      handleUpdateStatusById
    }
  }
})
